En este documento se presentan tres análisis con graficos interactivos para realizar con datos de Eventos de Notificación obligatoria provenientes de Datos Abiertos.

Para las visualizaciones interactivas se utilizaron los paquetes highcharter, echarts4r y Leaflet.

Instalación de paquetes y lectura de datos:


library(readxl)
library(tidyverse)
library(ISOweek)
library(tidyr)
library(highcharter)
library(tsibble)
library(lubridate)
library(geojsonsf)
library(echarts4r)
library(sf)
library(tmap)
library(leaflet)
library(DT)

datos_respiratorias <- 
  read_excel("RMD/RMD003_Analisis/datos/informacion-publica-respiratorias-nacional-hasta-20230706.xlsx")


##para otros años
 datos_respiratorias2 <- read_excel("RMD/RMD003_Analisis/datos/informacion-publica-respiratorias-nacional-hasta-20220905.xlsx")

Serie temporal de notificaciones de ETI (Enfermedad Tipo Influenza)

datos_eti <- datos_respiratorias %>%
  filter(evento_nombre == "Enfermedad tipo influenza (ETI)") %>%
  group_by(provincia_nombre, provincia_id, año, semanas_epidemiologicas) %>%
  summarise(conteo = sum(cantidad_casos))


datos_eti2 <- datos_respiratorias2 %>%
  filter(evento_nombre == "Enfermedad tipo influenza (ETI)",
         año != 2022) %>%
  group_by(provincia_nombre, provincia_id, año, semanas_epidemiologicas) %>%
  summarise(conteo = sum(cantidad_casos))

datos_eti <- rbind(datos_eti, datos_eti2)
head(datos_eti)
NA

Transformamos las variables Año y semanas_epidemiológicas en una variable con formato fecha de la semana. Para ello creo una función (convert_epiweek) por que las semana epi en el año 2020 tuvieron características que no me permiten hacen una transformación a fecha directa.

convert_epiweek <- function(year, week) {
  epiweek_date <- ifelse(year == 2020 & week == 53,
                         "2020-W53",
                         ifelse(year == 2020, ISOweek(ymd(
                           as.Date(paste(year, week, 1, sep = "-"), "%Y-%U-%u")
                         ) - weeks(1)),
                         ISOweek(as.Date(
                           paste(year, week, 1, sep = "-"), "%Y-%U-%u"
                         ))))
  return(epiweek_date)
}
datos_eti <- datos_eti %>% ungroup() %>%
  mutate(semana = yearweek(convert_epiweek(año, semanas_epidemiologicas)))

head(datos_eti)
NA

Ahora utilizo el paquete JohnCoene/echarts4r para hacer una visualización de la serie completa donde pueda agregar y quitar las provincias y ademas filtrar por el eje x, del tiempo para hacer zoom.

# chago conversiones de fecha
datos_eti$semana2 <- as.Date(datos_eti$semana)
datos_eti$semana3 <- as.POSIXct(datos_eti$semana)

ts_base = datos_eti %>%
  group_by(provincia_nombre, semana) %>% summarise(conteo = sum(conteo))
`summarise()` has grouped output by 'provincia_nombre'. You can override using the `.groups` argument.
ts_base$semana = as.character(ts_base$semana)

grid = list(
  provincia_nombre = unique(ts_base$provincia_nombre),
  semana = unique(as.character(ts_base$semana))
)

grid = expand.grid(grid)
data_grafico = left_join(grid, ts_base %>% as.data.frame)
Joining with `by = join_by(provincia_nombre, semana)`
data_grafico$conteo[is.na(data_grafico$conteo)] = 0

grafico =
  highchart() %>%
  hc_chart(type = "line",
           zoomType = 'xy') %>%
  hc_title(text = "Notificaciones de ETI por SEPI") %>%
  hc_xAxis(categories = data_grafico$semana) %>%
  hc_yAxis(title = list(text = "Notificaciones"))

provincias_seleccionadas = c("Buenos Aires", "Córdoba", "CABA", "Santa Fe", "Mendoza")

for (i in provincias_seleccionadas) {
  conteo = data_grafico$conteo[data_grafico$provincia_nombre == i]
  grafico = grafico %>% hc_add_series(name = i, data = conteo)
}

grafico

Graficos combinados

Se presenta a continuación un gráfico interactivo combinado utilizando highcharter. Se muestras graficos de barra para las semanas epis y un gráfico de torta para mostrar como se distribuye la edad en ese conjunto de datos.

EN primer lugar, preparo tablas para cada uno de estos graficos con los datos por semana y por grupo de edad.


torta <- datos_respiratorias %>%
  filter(año == 2022) %>%
  group_by(grupo_edad_desc) %>%
  summarise(casos = sum(cantidad_casos)) %>%
  mutate(porcent = round(casos / sum(casos) * 100, 1))

torta <- torta %>%
  mutate(
    grupo_edad_desc = case_when(
      grupo_edad_desc == "< 6 m" ~ "1. < 6 m",
      grupo_edad_desc == "6 a 11 m" ~ "2. 6 a 11 m",
      grupo_edad_desc == "10 a 14" ~ "6. 10 a 14",
      grupo_edad_desc == "12 a 23 m" ~ "3. 12 a 23 m",
      grupo_edad_desc == "15 a 19" ~ "7. 15 a 19",
      grupo_edad_desc == "2 a 4" ~ "4. 2 a 4",
      grupo_edad_desc == "20 a 24" ~ "8. 20 a 24",
      grupo_edad_desc == "25 a 34" ~ "9. 25 a 34",
      grupo_edad_desc == "35 a 44" ~ "10. 35 a 44",
      grupo_edad_desc == "45 a 64" ~ "11. 45 a 64",
      grupo_edad_desc == "5 a 9" ~ "5. 5 a 9",
      grupo_edad_desc == "65 a 74" ~ "12. 65 a 74",
      grupo_edad_desc == ">= a 75" ~ "13. >= a 75",
      grupo_edad_desc == "Edad Sin Esp." ~ "14. Edad Sin Esp.",
      TRUE ~ grupo_edad_desc
    )
  ) %>%
  arrange(as.numeric(substring(grupo_edad_desc, 1, 2)))

barras <- datos_respiratorias %>%
  filter(año == 2022) %>%
  group_by(semanas_epidemiologicas) %>%
  summarise(casos = sum(cantidad_casos)) %>%
  mutate(porcent = round(casos / sum(casos) * 100, 1))

torta
head(barras)

Código para el gráfico:


highchart() %>%
  hc_add_series(
    barras,
    "column", hcaes(
      x = semanas_epidemiologicas, y = casos
    ),
    name = "Casos de ETI",
    color="#2c7fb8"##ver porque no funciona
  ) %>%
  hc_add_series(
    torta, "pie", hcaes(
      name = grupo_edad_desc, y = porcent
    ),
    name = "Casos de ETI (%)"
  ) %>%
  ## Options for each type of series
  hc_plotOptions(
    series = list(
      showInLegend = FALSE,
      pointFormat = "{point.y}%",
      colorByPoint = FALSE
    ), 
    pie = list(
      center = c("65%", "10%"),
      size = 120,
      dataLabels = list(enabled = FALSE),
      colorByPoint = TRUE
    ),
    column = list(
                    groupPadding = 0,
                    pointPadding = 0,
                    borderWidth = 0.3,
                    borderColor = "white"
                  )
  ) %>%
  ## Axis
  hc_yAxis(
    title = list(text = "Número de casos"),
    labels = list(format = "{value}"),
    max = 50000
  ) %>%
  hc_xAxis(title = list(text = "Semana EPI"),
      categories = barras$semanas_epidemiologicas
  ) %>%
  ## Titles, subtitle, caption and credits
  hc_title(
    text = "Grafico de barras combinado con piechart: Notificaciones de ETI, año 2022"
  ) %>%
  hc_subtitle(
    text = "Ejemplo de grafico combinado para notificaciones de eti por semana y grupo de edad"
  ) %>%
  hc_caption(
    text = "Se representatan casos notificados de ETI al SNVS 2.0"
  ) %>%
  hc_credits(
    enabled = TRUE, text = "Fuente: Datos abiertos/ SNVS", href = "http://datos.salud.gob.ar/", style = list(fontSize = "12px")
  ) 

Mapas

Se van a presentar mapas de tasa de notificación de Sífilis en ambos sexos, para los años 2018 y 2020.

Leo los datos de datos abiertos que los tengo previamente descargados en una carpeta:

sifilis <-  read.csv("RMD/RMD003_Analisis/datos/tasa-sifilis-por-100-mil-habitantes-sexo-jurisdiccion-2018-2020-argentina_1.csv", encoding = "latin1")

tasas <- sifilis %>% 
  filter(anio==2018|anio==2020, id_sexo==3,
         id_jurisdiccion!=200) %>% 
  spread(anio, jurisdiccion_tasa_sifilis)

head(tasas)

Leo mapa de argentina en formato RDS:

mapa_arg <- readRDS(url("https://biogeo.ucdavis.edu/data/gadm3.6/Rsf/gadm36_ARG_1_sf.rds"))

mapa_arg <- sf::st_transform(mapa_arg, 5345)## EPSG:5345  posgar 2007/ Argentina faja 3
ggplot(data = mapa_arg) +
    geom_sf(crs=5345)

Unimos tabla de tasas con mapa:

tasas$jurisdiccion <- car::recode(tasas$jurisdiccion,"'CABA'='Ciudad de Buenos Aires'")

table(mapa_arg$NAME_1)

          Buenos Aires              Catamarca                  Chaco 
                     1                      1                      1 
                Chubut Ciudad de Buenos Aires                Córdoba 
                     1                      1                      1 
            Corrientes             Entre Ríos                Formosa 
                     1                      1                      1 
                 Jujuy               La Pampa               La Rioja 
                     1                      1                      1 
               Mendoza               Misiones                Neuquén 
                     1                      1                      1 
             Río Negro                  Salta               San Juan 
                     1                      1                      1 
              San Luis             Santa Cruz               Santa Fe 
                     1                      1                      1 
   Santiago del Estero       Tierra del Fuego                Tucumán 
                     1                      1                      1 
mapa_arg <- dplyr::left_join(mapa_arg, tasas, by = c("NAME_1"="jurisdiccion"))
names(mapa_arg) 
 [1] "GID_0"           "NAME_0"          "GID_1"           "NAME_1"         
 [5] "VARNAME_1"       "NL_NAME_1"       "TYPE_1"          "ENGTYPE_1"      
 [9] "CC_1"            "HASC_1"          "id_sexo"         "sexo"           
[13] "id_jurisdiccion" "2018"            "2020"            "geometry"       
class(mapa_arg)
[1] "sf"         "data.frame"
#mapa_arg_json <- sf_geojson(mapa_arg)
tmap_mode("view")
tm_shape(mapa_arg) +
    tm_polygons(c("2018", "2020"), n=4, style="jenks") +
    tm_facets(sync = TRUE, ncol = 2)
LS0tDQp0aXRsZTogIkFuw6FsaXNpcyBkZSBkYXRvcyBkZSBFdmVudG9zIGRlIE5vdGlmaWNhY2nDs24gT2JsaWdhdG9yaWEgLSBTTlZTIERhdG9zIGFiaWVydG9zIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0aGVtZTogY29zbW8NCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogdHJ1ZQ0KLS0tDQoNCkVuIGVzdGUgZG9jdW1lbnRvIHNlIHByZXNlbnRhbiB0cmVzIGFuw6FsaXNpcyBjb24gZ3JhZmljb3MgaW50ZXJhY3Rpdm9zIHBhcmEgcmVhbGl6YXIgY29uIGRhdG9zIGRlIEV2ZW50b3MgZGUgTm90aWZpY2FjacOzbiBvYmxpZ2F0b3JpYSBwcm92ZW5pZW50ZXMgZGUgRGF0b3MgQWJpZXJ0b3MuIA0KDQpQYXJhIGxhcyB2aXN1YWxpemFjaW9uZXMgaW50ZXJhY3RpdmFzIHNlIHV0aWxpemFyb24gbG9zIHBhcXVldGVzICpoaWdoY2hhcnRlciosICplY2hhcnRzNHIqIHkgKkxlYWZsZXQqLg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShrbGlwcHkpDQpgYGANCg0KYGBge3Iga2xpcHB5LCBlY2hvPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQojcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInJsZXN1ci9rbGlwcHkiKQ0Ka2xpcHB5OjprbGlwcHkoY29sb3IgPSAnZGFya3JlZCcsIHRvb2x0aXBfbWVzc2FnZSA9ICdDbGljayB0byBjb3B5JywgdG9vbHRpcF9zdWNjZXNzID0gJ0RvbmUnLHBvc2l0aW9uID0gYygndG9wJywgJ3JpZ2h0JykpDQoNCmBgYA0KDQojIEluc3RhbGFjacOzbiBkZSBwYXF1ZXRlcyB5IGxlY3R1cmEgZGUgZGF0b3M6DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNsYXNzLnNvdXJjZT0na2xpcHB5J30NCg0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoSVNPd2VlaykNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQ0KbGlicmFyeSh0c2liYmxlKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGdlb2pzb25zZikNCmxpYnJhcnkoZWNoYXJ0czRyKQ0KbGlicmFyeShzZikNCmxpYnJhcnkodG1hcCkNCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkoRFQpDQoNCmRhdG9zX3Jlc3BpcmF0b3JpYXMgPC0gDQogIHJlYWRfZXhjZWwoIlJNRC9STUQwMDNfQW5hbGlzaXMvZGF0b3MvaW5mb3JtYWNpb24tcHVibGljYS1yZXNwaXJhdG9yaWFzLW5hY2lvbmFsLWhhc3RhLTIwMjMwNzA2Lnhsc3giKQ0KDQoNCiMjcGFyYSBvdHJvcyBhw7Fvcw0KIGRhdG9zX3Jlc3BpcmF0b3JpYXMyIDwtIHJlYWRfZXhjZWwoIlJNRC9STUQwMDNfQW5hbGlzaXMvZGF0b3MvaW5mb3JtYWNpb24tcHVibGljYS1yZXNwaXJhdG9yaWFzLW5hY2lvbmFsLWhhc3RhLTIwMjIwOTA1Lnhsc3giKQ0KDQpgYGANCg0KDQojIFNlcmllIHRlbXBvcmFsIGRlIG5vdGlmaWNhY2lvbmVzIGRlIEVUSSAoRW5mZXJtZWRhZCBUaXBvIEluZmx1ZW56YSkNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KZGF0b3NfZXRpIDwtIGRhdG9zX3Jlc3BpcmF0b3JpYXMgJT4lDQogIGZpbHRlcihldmVudG9fbm9tYnJlID09ICJFbmZlcm1lZGFkIHRpcG8gaW5mbHVlbnphIChFVEkpIikgJT4lDQogIGdyb3VwX2J5KHByb3ZpbmNpYV9ub21icmUsIHByb3ZpbmNpYV9pZCwgYcOxbywgc2VtYW5hc19lcGlkZW1pb2xvZ2ljYXMpICU+JQ0KICBzdW1tYXJpc2UoY29udGVvID0gc3VtKGNhbnRpZGFkX2Nhc29zKSkNCg0KZGF0b3NfZXRpMiA8LSBkYXRvc19yZXNwaXJhdG9yaWFzMiAlPiUNCiAgZmlsdGVyKGV2ZW50b19ub21icmUgPT0gIkVuZmVybWVkYWQgdGlwbyBpbmZsdWVuemEgKEVUSSkiLA0KICAgICAgICAgYcOxbyAhPSAyMDIyKSAlPiUNCiAgZ3JvdXBfYnkocHJvdmluY2lhX25vbWJyZSwgcHJvdmluY2lhX2lkLCBhw7FvLCBzZW1hbmFzX2VwaWRlbWlvbG9naWNhcykgJT4lDQogIHN1bW1hcmlzZShjb250ZW8gPSBzdW0oY2FudGlkYWRfY2Fzb3MpKQ0KDQpkYXRvc19ldGkgPC0gcmJpbmQoZGF0b3NfZXRpLCBkYXRvc19ldGkyKQ0KRFQ6OmRhdGEudGFibGUoaGVhZChkYXRvc19ldGkpKQ0KDQpgYGANCg0KVHJhbnNmb3JtYW1vcyBsYXMgdmFyaWFibGVzIEHDsW8geSBzZW1hbmFzX2VwaWRlbWlvbMOzZ2ljYXMgZW4gdW5hIHZhcmlhYmxlIGNvbiBmb3JtYXRvIGZlY2hhIGRlIGxhIHNlbWFuYS4gUGFyYSBlbGxvIGNyZW8gdW5hIGZ1bmNpw7NuIChjb252ZXJ0X2VwaXdlZWspIHBvciBxdWUgbGFzIHNlbWFuYSBlcGkgZW4gZWwgYcOxbyAyMDIwIHR1dmllcm9uIGNhcmFjdGVyw61zdGljYXMgcXVlIG5vIG1lIHBlcm1pdGVuIGhhY2VuIHVuYSB0cmFuc2Zvcm1hY2nDs24gYSBmZWNoYSBkaXJlY3RhLg0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpjb252ZXJ0X2VwaXdlZWsgPC0gZnVuY3Rpb24oeWVhciwgd2Vlaykgew0KICBlcGl3ZWVrX2RhdGUgPC0gaWZlbHNlKHllYXIgPT0gMjAyMCAmIHdlZWsgPT0gNTMsDQogICAgICAgICAgICAgICAgICAgICAgICAgIjIwMjAtVzUzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoeWVhciA9PSAyMDIwLCBJU093ZWVrKHltZCgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLkRhdGUocGFzdGUoeWVhciwgd2VlaywgMSwgc2VwID0gIi0iKSwgIiVZLSVVLSV1IikNCiAgICAgICAgICAgICAgICAgICAgICAgICApIC0gd2Vla3MoMSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIElTT3dlZWsoYXMuRGF0ZSgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKHllYXIsIHdlZWssIDEsIHNlcCA9ICItIiksICIlWS0lVS0ldSINCiAgICAgICAgICAgICAgICAgICAgICAgICApKSkpDQogIHJldHVybihlcGl3ZWVrX2RhdGUpDQp9DQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGF0b3NfZXRpIDwtIGRhdG9zX2V0aSAlPiUgdW5ncm91cCgpICU+JQ0KICBtdXRhdGUoc2VtYW5hID0geWVhcndlZWsoY29udmVydF9lcGl3ZWVrKGHDsW8sIHNlbWFuYXNfZXBpZGVtaW9sb2dpY2FzKSkpDQoNCkRUOjpkYXRhLnRhYmxlKGhlYWQoZGF0b3NfZXRpKSkNCmBgYA0KQWhvcmEgdXRpbGl6byBlbCBwYXF1ZXRlICpKb2huQ29lbmUvZWNoYXJ0czRyKiBwYXJhIGhhY2VyIHVuYSB2aXN1YWxpemFjacOzbiBkZSBsYSBzZXJpZSBjb21wbGV0YSBkb25kZSBwdWVkYSBhZ3JlZ2FyIHkgcXVpdGFyIGxhcyBwcm92aW5jaWFzIHkgYWRlbWFzIGZpbHRyYXIgcG9yIGVsIGVqZSB4LCBkZWwgdGllbXBvIHBhcmEgaGFjZXIgem9vbS4gDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIGNoYWdvIGNvbnZlcnNpb25lcyBkZSBmZWNoYQ0KZGF0b3NfZXRpJHNlbWFuYTIgPC0gYXMuRGF0ZShkYXRvc19ldGkkc2VtYW5hKQ0KZGF0b3NfZXRpJHNlbWFuYTMgPC0gYXMuUE9TSVhjdChkYXRvc19ldGkkc2VtYW5hKQ0KDQpgYGANCg0KDQpgYGB7cn0NCg0KdHNfYmFzZSA9IGRhdG9zX2V0aSAlPiUNCiAgZ3JvdXBfYnkocHJvdmluY2lhX25vbWJyZSwgc2VtYW5hKSAlPiUgc3VtbWFyaXNlKGNvbnRlbyA9IHN1bShjb250ZW8pKQ0KdHNfYmFzZSRzZW1hbmEgPSBhcy5jaGFyYWN0ZXIodHNfYmFzZSRzZW1hbmEpDQoNCmdyaWQgPSBsaXN0KA0KICBwcm92aW5jaWFfbm9tYnJlID0gdW5pcXVlKHRzX2Jhc2UkcHJvdmluY2lhX25vbWJyZSksDQogIHNlbWFuYSA9IHVuaXF1ZShhcy5jaGFyYWN0ZXIodHNfYmFzZSRzZW1hbmEpKQ0KKQ0KDQpncmlkID0gZXhwYW5kLmdyaWQoZ3JpZCkNCmRhdGFfZ3JhZmljbyA9IGxlZnRfam9pbihncmlkLCB0c19iYXNlICU+JSBhcy5kYXRhLmZyYW1lKQ0KZGF0YV9ncmFmaWNvJGNvbnRlb1tpcy5uYShkYXRhX2dyYWZpY28kY29udGVvKV0gPSAwDQoNCmBgYA0KDQpgYGB7cn0NCg0KZ3JhZmljbyA9DQogIGhpZ2hjaGFydCgpICU+JQ0KICBoY19jaGFydCh0eXBlID0gImxpbmUiLA0KICAgICAgICAgICB6b29tVHlwZSA9ICd4eScpICU+JQ0KICBoY190aXRsZSh0ZXh0ID0gIk5vdGlmaWNhY2lvbmVzIGRlIEVUSSBwb3IgU0VQSSIpICU+JQ0KICBoY194QXhpcyhjYXRlZ29yaWVzID0gZGF0YV9ncmFmaWNvJHNlbWFuYSkgJT4lDQogIGhjX3lBeGlzKHRpdGxlID0gbGlzdCh0ZXh0ID0gIk5vdGlmaWNhY2lvbmVzIikpDQoNCnByb3ZpbmNpYXNfc2VsZWNjaW9uYWRhcyA9IGMoIkJ1ZW5vcyBBaXJlcyIsICJDw7NyZG9iYSIsICJDQUJBIiwgIlNhbnRhIEZlIiwgIk1lbmRvemEiKQ0KDQpmb3IgKGkgaW4gcHJvdmluY2lhc19zZWxlY2Npb25hZGFzKSB7DQogIGNvbnRlbyA9IGRhdGFfZ3JhZmljbyRjb250ZW9bZGF0YV9ncmFmaWNvJHByb3ZpbmNpYV9ub21icmUgPT0gaV0NCiAgZ3JhZmljbyA9IGdyYWZpY28gJT4lIGhjX2FkZF9zZXJpZXMobmFtZSA9IGksIGRhdGEgPSBjb250ZW8pDQp9DQoNCmdyYWZpY28NCg0KYGBgDQoNCiMgR3JhZmljb3MgY29tYmluYWRvcw0KDQpTZSBwcmVzZW50YSBhIGNvbnRpbnVhY2nDs24gdW4gZ3LDoWZpY28gaW50ZXJhY3Rpdm8gY29tYmluYWRvIHV0aWxpemFuZG8gKmhpZ2hjaGFydGVyKi4gU2UgbXVlc3RyYXMgZ3JhZmljb3MgZGUgYmFycmEgcGFyYSBsYXMgc2VtYW5hcyBlcGlzIHkgdW4gZ3LDoWZpY28gZGUgdG9ydGEgcGFyYSBtb3N0cmFyIGNvbW8gc2UgZGlzdHJpYnV5ZSBsYSBlZGFkIGVuIGVzZSBjb25qdW50byBkZSBkYXRvcy4NCg0KRU4gcHJpbWVyIGx1Z2FyLCBwcmVwYXJvIHRhYmxhcyBwYXJhIGNhZGEgdW5vIGRlIGVzdG9zIGdyYWZpY29zIGNvbiBsb3MgZGF0b3MgcG9yIHNlbWFuYSB5IHBvciBncnVwbyBkZSBlZGFkLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQp0b3J0YSA8LSBkYXRvc19yZXNwaXJhdG9yaWFzICU+JQ0KICBmaWx0ZXIoYcOxbyA9PSAyMDIyKSAlPiUNCiAgZ3JvdXBfYnkoZ3J1cG9fZWRhZF9kZXNjKSAlPiUNCiAgc3VtbWFyaXNlKGNhc29zID0gc3VtKGNhbnRpZGFkX2Nhc29zKSkgJT4lDQogIG11dGF0ZShwb3JjZW50ID0gcm91bmQoY2Fzb3MgLyBzdW0oY2Fzb3MpICogMTAwLCAxKSkNCg0KdG9ydGEgPC0gdG9ydGEgJT4lDQogIG11dGF0ZSgNCiAgICBncnVwb19lZGFkX2Rlc2MgPSBjYXNlX3doZW4oDQogICAgICBncnVwb19lZGFkX2Rlc2MgPT0gIjwgNiBtIiB+ICIxLiA8IDYgbSIsDQogICAgICBncnVwb19lZGFkX2Rlc2MgPT0gIjYgYSAxMSBtIiB+ICIyLiA2IGEgMTEgbSIsDQogICAgICBncnVwb19lZGFkX2Rlc2MgPT0gIjEwIGEgMTQiIH4gIjYuIDEwIGEgMTQiLA0KICAgICAgZ3J1cG9fZWRhZF9kZXNjID09ICIxMiBhIDIzIG0iIH4gIjMuIDEyIGEgMjMgbSIsDQogICAgICBncnVwb19lZGFkX2Rlc2MgPT0gIjE1IGEgMTkiIH4gIjcuIDE1IGEgMTkiLA0KICAgICAgZ3J1cG9fZWRhZF9kZXNjID09ICIyIGEgNCIgfiAiNC4gMiBhIDQiLA0KICAgICAgZ3J1cG9fZWRhZF9kZXNjID09ICIyMCBhIDI0IiB+ICI4LiAyMCBhIDI0IiwNCiAgICAgIGdydXBvX2VkYWRfZGVzYyA9PSAiMjUgYSAzNCIgfiAiOS4gMjUgYSAzNCIsDQogICAgICBncnVwb19lZGFkX2Rlc2MgPT0gIjM1IGEgNDQiIH4gIjEwLiAzNSBhIDQ0IiwNCiAgICAgIGdydXBvX2VkYWRfZGVzYyA9PSAiNDUgYSA2NCIgfiAiMTEuIDQ1IGEgNjQiLA0KICAgICAgZ3J1cG9fZWRhZF9kZXNjID09ICI1IGEgOSIgfiAiNS4gNSBhIDkiLA0KICAgICAgZ3J1cG9fZWRhZF9kZXNjID09ICI2NSBhIDc0IiB+ICIxMi4gNjUgYSA3NCIsDQogICAgICBncnVwb19lZGFkX2Rlc2MgPT0gIj49IGEgNzUiIH4gIjEzLiA+PSBhIDc1IiwNCiAgICAgIGdydXBvX2VkYWRfZGVzYyA9PSAiRWRhZCBTaW4gRXNwLiIgfiAiMTQuIEVkYWQgU2luIEVzcC4iLA0KICAgICAgVFJVRSB+IGdydXBvX2VkYWRfZGVzYw0KICAgICkNCiAgKSAlPiUNCiAgYXJyYW5nZShhcy5udW1lcmljKHN1YnN0cmluZyhncnVwb19lZGFkX2Rlc2MsIDEsIDIpKSkNCg0KYmFycmFzIDwtIGRhdG9zX3Jlc3BpcmF0b3JpYXMgJT4lDQogIGZpbHRlcihhw7FvID09IDIwMjIpICU+JQ0KICBncm91cF9ieShzZW1hbmFzX2VwaWRlbWlvbG9naWNhcykgJT4lDQogIHN1bW1hcmlzZShjYXNvcyA9IHN1bShjYW50aWRhZF9jYXNvcykpICU+JQ0KICBtdXRhdGUocG9yY2VudCA9IHJvdW5kKGNhc29zIC8gc3VtKGNhc29zKSAqIDEwMCwgMSkpDQoNCkRUOjpkYXRhLnRhYmxlKHRvcnRhKQ0KRFQ6OmRhdGEudGFibGUoaGVhZChiYXJyYXMpKQ0KYGBgDQoNCkPDs2RpZ28gcGFyYSBlbCBncsOhZmljbzoNCg0KYGBge3J9DQoNCmhpZ2hjaGFydCgpICU+JQ0KICBoY19hZGRfc2VyaWVzKA0KICAgIGJhcnJhcywNCiAgICAiY29sdW1uIiwgaGNhZXMoDQogICAgICB4ID0gc2VtYW5hc19lcGlkZW1pb2xvZ2ljYXMsIHkgPSBjYXNvcw0KICAgICksDQogICAgbmFtZSA9ICJDYXNvcyBkZSBFVEkiLA0KICAgIGNvbG9yPSIjMmM3ZmI4IiMjdmVyIHBvcnF1ZSBubyBmdW5jaW9uYQ0KICApICU+JQ0KICBoY19hZGRfc2VyaWVzKA0KICAgIHRvcnRhLCAicGllIiwgaGNhZXMoDQogICAgICBuYW1lID0gZ3J1cG9fZWRhZF9kZXNjLCB5ID0gcG9yY2VudA0KICAgICksDQogICAgbmFtZSA9ICJDYXNvcyBkZSBFVEkgKCUpIg0KICApICU+JQ0KICAjIyBPcHRpb25zIGZvciBlYWNoIHR5cGUgb2Ygc2VyaWVzDQogIGhjX3Bsb3RPcHRpb25zKA0KICAgIHNlcmllcyA9IGxpc3QoDQogICAgICBzaG93SW5MZWdlbmQgPSBGQUxTRSwNCiAgICAgIHBvaW50Rm9ybWF0ID0gIntwb2ludC55fSUiLA0KICAgICAgY29sb3JCeVBvaW50ID0gRkFMU0UNCiAgICApLCANCiAgICBwaWUgPSBsaXN0KA0KICAgICAgY2VudGVyID0gYygiNjUlIiwgIjEwJSIpLA0KICAgICAgc2l6ZSA9IDEyMCwNCiAgICAgIGRhdGFMYWJlbHMgPSBsaXN0KGVuYWJsZWQgPSBGQUxTRSksDQogICAgICBjb2xvckJ5UG9pbnQgPSBUUlVFDQogICAgKSwNCiAgICBjb2x1bW4gPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICBncm91cFBhZGRpbmcgPSAwLA0KICAgICAgICAgICAgICAgICAgICBwb2ludFBhZGRpbmcgPSAwLA0KICAgICAgICAgICAgICAgICAgICBib3JkZXJXaWR0aCA9IDAuMywNCiAgICAgICAgICAgICAgICAgICAgYm9yZGVyQ29sb3IgPSAid2hpdGUiDQogICAgICAgICAgICAgICAgICApDQogICkgJT4lDQogICMjIEF4aXMNCiAgaGNfeUF4aXMoDQogICAgdGl0bGUgPSBsaXN0KHRleHQgPSAiTsO6bWVybyBkZSBjYXNvcyIpLA0KICAgIGxhYmVscyA9IGxpc3QoZm9ybWF0ID0gInt2YWx1ZX0iKSwNCiAgICBtYXggPSA1MDAwMA0KICApICU+JQ0KICBoY194QXhpcyh0aXRsZSA9IGxpc3QodGV4dCA9ICJTZW1hbmEgRVBJIiksDQogICAgICBjYXRlZ29yaWVzID0gYmFycmFzJHNlbWFuYXNfZXBpZGVtaW9sb2dpY2FzDQogICkgJT4lDQogICMjIFRpdGxlcywgc3VidGl0bGUsIGNhcHRpb24gYW5kIGNyZWRpdHMNCiAgaGNfdGl0bGUoDQogICAgdGV4dCA9ICJHcmFmaWNvIGRlIGJhcnJhcyBjb21iaW5hZG8gY29uIHBpZWNoYXJ0OiBOb3RpZmljYWNpb25lcyBkZSBFVEksIGHDsW8gMjAyMiINCiAgKSAlPiUNCiAgaGNfc3VidGl0bGUoDQogICAgdGV4dCA9ICJFamVtcGxvIGRlIGdyYWZpY28gY29tYmluYWRvIHBhcmEgbm90aWZpY2FjaW9uZXMgZGUgZXRpIHBvciBzZW1hbmEgeSBncnVwbyBkZSBlZGFkIg0KICApICU+JQ0KICBoY19jYXB0aW9uKA0KICAgIHRleHQgPSAiU2UgcmVwcmVzZW50YXRhbiBjYXNvcyBub3RpZmljYWRvcyBkZSBFVEkgYWwgU05WUyAyLjAiDQogICkgJT4lDQogIGhjX2NyZWRpdHMoDQogICAgZW5hYmxlZCA9IFRSVUUsIHRleHQgPSAiRnVlbnRlOiBEYXRvcyBhYmllcnRvcy8gU05WUyIsIGhyZWYgPSAiaHR0cDovL2RhdG9zLnNhbHVkLmdvYi5hci8iLCBzdHlsZSA9IGxpc3QoZm9udFNpemUgPSAiMTJweCIpDQogICkgDQpgYGANCg0KIyBNYXBhcw0KDQpTZSB2YW4gYSBwcmVzZW50YXIgbWFwYXMgZGUgdGFzYSBkZSBub3RpZmljYWNpw7NuIGRlIFPDrWZpbGlzIGVuIGFtYm9zIHNleG9zLCBwYXJhIGxvcyBhw7FvcyAyMDE4IHkgMjAyMC4gDQoNCkxlbyBsb3MgZGF0b3MgZGUgZGF0b3MgYWJpZXJ0b3MgcXVlIGxvcyB0ZW5nbyBwcmV2aWFtZW50ZSBkZXNjYXJnYWRvcyBlbiB1bmEgY2FycGV0YToNCg0KYGBge3J9DQpzaWZpbGlzIDwtICByZWFkLmNzdigiUk1EL1JNRDAwM19BbmFsaXNpcy9kYXRvcy90YXNhLXNpZmlsaXMtcG9yLTEwMC1taWwtaGFiaXRhbnRlcy1zZXhvLWp1cmlzZGljY2lvbi0yMDE4LTIwMjAtYXJnZW50aW5hXzEuY3N2IiwgZW5jb2RpbmcgPSAibGF0aW4xIikNCg0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCnRhc2FzIDwtIHNpZmlsaXMgJT4lIA0KICBmaWx0ZXIoYW5pbz09MjAxOHxhbmlvPT0yMDIwLCBpZF9zZXhvPT0zLA0KICAgICAgICAgaWRfanVyaXNkaWNjaW9uIT0yMDApICU+JSANCiAgc3ByZWFkKGFuaW8sIGp1cmlzZGljY2lvbl90YXNhX3NpZmlsaXMpDQoNCkRUOjpkYXRhLnRhYmxlKGhlYWQodGFzYXMpKQ0KDQpgYGANCg0KTGVvIG1hcGEgZGUgYXJnZW50aW5hIGVuIGZvcm1hdG8gUkRTOg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbWFwYV9hcmcgPC0gcmVhZFJEUyh1cmwoImh0dHBzOi8vYmlvZ2VvLnVjZGF2aXMuZWR1L2RhdGEvZ2FkbTMuNi9Sc2YvZ2FkbTM2X0FSR18xX3NmLnJkcyIpKQ0KDQptYXBhX2FyZyA8LSBzZjo6c3RfdHJhbnNmb3JtKG1hcGFfYXJnLCA1MzQ1KSMjIEVQU0c6NTM0NSAgcG9zZ2FyIDIwMDcvIEFyZ2VudGluYSBmYWphIDMNCmdncGxvdChkYXRhID0gbWFwYV9hcmcpICsNCiAgICBnZW9tX3NmKGNycz01MzQ1KQ0KYGBgDQpVbmltb3MgdGFibGEgZGUgdGFzYXMgY29uIG1hcGE6DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp0YXNhcyRqdXJpc2RpY2Npb24gPC0gY2FyOjpyZWNvZGUodGFzYXMkanVyaXNkaWNjaW9uLCInQ0FCQSc9J0NpdWRhZCBkZSBCdWVub3MgQWlyZXMnIikNCg0KdGFibGUobWFwYV9hcmckTkFNRV8xKQ0KDQptYXBhX2FyZyA8LSBkcGx5cjo6bGVmdF9qb2luKG1hcGFfYXJnLCB0YXNhcywgYnkgPSBjKCJOQU1FXzEiPSJqdXJpc2RpY2Npb24iKSkNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp0bWFwX21vZGUoInZpZXciKQ0KdG1fc2hhcGUobWFwYV9hcmcpICsNCiAgICB0bV9wb2x5Z29ucyhjKCIyMDE4IiwgIjIwMjAiKSwgbj00LCBzdHlsZT0iamVua3MiKSArDQogICAgdG1fZmFjZXRzKHN5bmMgPSBUUlVFLCBuY29sID0gMikNCmBgYA0KDQo=